﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;

namespace nhCore.Modbus
{
    /// <summary>
    /// 本机为从机收到主机命令，组返回帧
    /// </summary>
    public abstract class ReturnFrame : BaseFrame
    {
        protected ReturnFrame(byte address)
        {
            Address = address;
        }

        /// <summary>
        /// 组成完整帧，根据命令中的数据返回
        /// </summary>
        /// <param name="cmdData">命令中数据</param>
        /// <param name="weatherData">气象数据</param>
        /// <returns></returns>
        public abstract byte[] GetFrame(byte[] cmdData, byte[] weatherData);
    }

    /// <summary>
    /// 读寄存器，实时数据
    /// </summary>
    public class ReadRegReturnFrame : ReturnFrame
    {
        public ReadRegReturnFrame(byte address): base(address)
        {
            Code = 0x04;
        }

        public override byte[] GetFrame(byte[] cmdData, byte[] weatherData)
        {
            int dataLength = cmdData[3] << 1;//返回帧长度保存在一个字节内，这里高位无意义
            int startReg = ((UInt16)cmdData[0] << 8) + cmdData[1];
            byte[] frame = new byte[dataLength + 5];
            frame[0] = Address;
            frame[1] = Code;
            frame[2] = (byte)dataLength;
            for (int i = 0; (i < dataLength) && (((startReg << 1) + i) < weatherData.Length); i++)
            {
                frame[3 + i] = weatherData[(startReg << 1) + i];
            }
            AddCrc(ref frame);

            return frame;
        }
    }

    /// <summary>
    /// 读保存寄存器，实时数据
    /// </summary>
    public class ReadHoldRegReturnFrame : ReadRegReturnFrame
    {
        public ReadHoldRegReturnFrame(byte address) : base(address)
        {
            Code = 0x03;
        }
    }

    /// <summary>
    /// 读历史数据
    /// </summary>
    public class ReadHistoryReturnFrame : ReturnFrame
    {
        public static int MaxHistoryData { get; set; }

        public ReadHistoryReturnFrame(byte address) : base(address)
        {
            Code = 0x41;
        }

        public override byte[] GetFrame(byte[] cmdData, byte[] weatherData)
        {
            byte[] frame = new byte[54 + 5];
            frame[0] = Address;
            frame[1] = Code;
            frame[2] = 54;
            DateTime time = DateTime.Now;
            //根据命令数据时间前推
            uint temp = 0;
            for (int i = 0; i < 4; i++)
            {
                temp <<= 8;
                temp |= cmdData[i];
            }
            if (temp < MaxHistoryData)
            {
                time = time.AddMinutes(-temp * 10);

                frame[3] = (byte)(time.Year - 2000);
                frame[4] = (byte)time.Month;
                frame[5] = (byte)time.Day;
                frame[6] = (byte)time.Hour;
                frame[7] = (byte)((time.Minute / 10) * 10);//时间取整10分钟
                frame[8] = 0;
            }
            else
            {
                for (int i = 0; i < 6; i++)
                    frame[3 + i] = 0xFF;
            }
            for (int i = 6; (i < 54); i++)
            {
                frame[3 + i] = weatherData[i];
            }
            AddCrc(ref frame);

            return frame;
        }
    }

    /// <summary>
    /// 写多个寄存器，校时
    /// </summary>
    public class WriteMultRegReturnFrame : ReturnFrame
    {
        public WriteMultRegReturnFrame(byte address) : base(address)
        {
            Code = 0x10;
        }

        public override byte[] GetFrame(byte[] cmdData, byte[] weatherData)
        {
            byte[] frame = null;
            int dataLength = cmdData[3] << 1;//返回帧长度保存在一个字节内，这里高位无意义
            int startReg = ((UInt16)cmdData[0] << 8) + cmdData[1];
            if ((startReg == 0) && (dataLength == 6))
            {
                frame = new byte[8] { Address, Code, 0, 0, 0, 3, 0, 0 };
                AddCrc(ref frame);
            }
            return frame;
        }
    }
}
